package com.cryptoneedle.center.source.service.metadata;


import cn.hutool.v7.core.tree.MapTree;
import cn.hutool.v7.core.tree.TreeNode;
import cn.hutool.v7.core.tree.TreeNodeConfig;
import cn.hutool.v7.core.tree.TreeUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.bubbles.engine.data.core.repository.BaseRepository;
import com.bubbles.engine.data.core.service.BaseService;
import com.cryptoneedle.center.source.entity.metadata.SourceServer;
import com.cryptoneedle.center.source.enums.TreeNodeType;
import com.cryptoneedle.center.source.key.metadata.SourceServerKey;
import com.cryptoneedle.center.source.properties.SshProperties;
import com.cryptoneedle.center.source.repository.metadata.SourceServerRepository;
import com.cryptoneedle.center.source.service.constraint.*;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDimensionService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDorisAnalyzeColumnService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceDorisAnalyzeTableService;
import com.cryptoneedle.center.source.service.enhance.SourceEnhanceIncrementService;
import com.cryptoneedle.center.source.util.SshManager;
import com.cryptoneedle.center.source.vo.SourceTreeDto;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>description: 源数据源-服务器 </p>
 *
 * @author CryptoNeedle
 * @date 2025-06-20
 */
@DS("pg")
@Slf4j
@Service
public class SourceServerService extends BaseService<SourceServer, SourceServerKey> {
    
    @Resource
    private SourceServerRepository sourceServerRepository;
    
    @Override
    public BaseRepository<SourceServer, SourceServerKey> getRepository() {
        return this.sourceServerRepository;
    }
    
    @Resource
    private SourceJdbcService sourceJdbcService;
    
    @Resource
    private SourceServerService sourceServerService;
    
    @Resource
    private SourceCatalogService sourceCatalogService;
    
    @Resource
    private SourceDatabaseService sourceDatabaseService;
    
    @Resource
    private SourceTableService sourceTableService;
    
    @Resource
    private SourceColumnService sourceColumnService;
    
    @Resource
    private SourceConstraintPrimaryService sourceConstraintPrimaryService;
    
    @Resource
    private SourceConstraintUniqueService sourceConstraintUniqueService;
    
    @Resource
    private SourceConstraintForeignService sourceConstraintForeignService;
    
    @Resource
    private SourceConstraintCheckService sourceConstraintCheckService;
    
    @Resource
    private SourceIndexUniqueService sourceIndexUniqueService;
    
    @Resource
    private SourceEnhanceDorisAnalyzeTableService sourceEnhanceDorisAnalyzeTableService;
    
    @Resource
    private SourceEnhanceDorisAnalyzeColumnService sourceEnhanceDorisAnalyzeColumnService;
    
    @Resource
    private SourceEnhanceIncrementService sourceEnhanceIncrementService;
    
    @Resource
    private SourceEnhanceDimensionService sourceEnhanceDimensionService;
    
    @Resource
    private SshProperties sshProperties;
    
    @Resource
    private SshManager sshManager;
    
    public List<MapTree<Object>> tree(Boolean displayServer, Boolean displayTable) {
        
        List<SourceTreeDto> sourceTreeDtos = new ArrayList<>();
        
        // 服务器
        if (displayServer) {
            sourceTreeDtos.addAll(sourceServerService
                                          .findAll()
                                          .stream()
                                          .map(sourceServer -> new SourceTreeDto()
                                                  .setId(sourceServer.getInetAddress())
                                                  .setParentId(null)
                                                  .setName(sourceServer.getInetAddress())
                                                  .setNodeType(TreeNodeType.SERVER.name())
                                                  .setDatabaseType(null)
                                                  .setEnabled(true))
                                          .toList());
        }
        
        // Catalog
        sourceTreeDtos.addAll(sourceCatalogService
                                      .findAll()
                                      .stream()
                                      .map(sourceCatalog -> new SourceTreeDto()
                                              .setId(sourceCatalog.getSourceCatalogName())
                                              .setParentId(displayServer ? sourceCatalog.getServer().getInetAddress() : null)
                                              .setName(sourceCatalog.getSourceCatalogName())
                                              .setNodeType(TreeNodeType.CATALOG.name())
                                              .setDatabaseType(sourceCatalog.getJdbc().getDatabaseType())
                                              .setEnabled(sourceCatalog.getSourceCatalogEnabled()))
                                      .toList());
        
        // 数据库
        sourceTreeDtos.addAll(sourceDatabaseService
                                      .listEnabled()
                                      .stream()
                                      .map(sourceDatabase -> new SourceTreeDto()
                                              .setId(sourceDatabase.getSourceDatabaseName())
                                              .setParentId(sourceDatabase.getSourceCatalogName())
                                              .setName(sourceDatabase.getSourceDatabaseName())
                                              .setNodeType(TreeNodeType.DATABASE.name())
                                              .setDatabaseType(null)
                                              .setEnabled(sourceDatabase.getSourceDatabaseEnabled()))
                                      .toList());
        
        // 表
        if (displayTable) {
            sourceTreeDtos.addAll(sourceTableService
                                          .listEnabled()
                                          .stream()
                                          .map(sourceTable -> new SourceTreeDto()
                                                  .setId(sourceTable.getSourceTableName())
                                                  .setParentId(sourceTable.getSourceDatabaseName())
                                                  .setName(sourceTable.getSourceTableName())
                                                  .setNodeType(TreeNodeType.TABLE.name())
                                                  .setDatabaseType(null)
                                                  .setEnabled(sourceTable.getSourceTableEnabled()))
                                          .toList());
        }
        
        AtomicInteger sort = new AtomicInteger();
        List<TreeNode<String>> treeNodeList = sourceTreeDtos
                .stream()
                .map(treeDto -> new TreeNode<String>()
                        .setId(treeDto.getId())
                        .setParentId(treeDto.getParentId())
                        .setName(treeDto.getName())
                        .setWeight(sort.getAndIncrement())
                        .setExtra(new HashMap<>() {{
                            put("nodeType", treeDto.getNodeType());
                            put("databaseType", treeDto.getDatabaseType());
                        }}))
                .toList();
        
        TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
        treeNodeConfig.setNameKey("name");
        treeNodeConfig.setDeep(4);
        
        return TreeUtil.build(treeNodeList, null, treeNodeConfig, (object, treeNode) -> {
            treeNode.setParentId(object.getParentId());
            treeNode.setId(object.getId());
            treeNode.setName(object.getName());
            treeNode.setWeight(object.getWeight());
            treeNode.putExtra("nodeType", object.getExtra().get("nodeType"));
            treeNode.putExtra("databaseType", object.getExtra().get("databaseType"));
        });
    }
    
    @Transactional
    public void clearWithoutRelation(SourceServer sourceServer) {
        if (sourceServer.getSourceJdbcs().isEmpty()) {
            sourceServerRepository.delete(sourceServer);
        }
    }
}